#region
/* Adoor.NET - Object/Relational mapping framework leveraging ADO.NET`s powerful disconnected mode.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *  
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *  
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#endregion

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml;
using Adoor.Object.Domain;
using Adoor.Object.Entity;

namespace Adoor.Object.Relational
{
    public abstract class InverseReferenceMapping<TReference> :
        IService, IReferenceMapping
        , IInverseReference
    {
        private ReferenceData referenceData;
        protected string backRole;

        public InverseReferenceMapping(ReferenceData referenceData, XmlNode metadata)
        {
            this.referenceData = referenceData;
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable());
            nsmgr.AddNamespace("typing", "urn:xmd-typing");
            nsmgr.AddNamespace("mapping", "urn:xmd-mapping");
            this.backRole = metadata.ParentNode.SelectSingleNode("typing:reference/@parent", nsmgr).Value;

            this.ReferenceData.RegisterService(typeof(IInverseReference), this);
        }

        public void Initialize()
        {
            this.ReferenceData.RegisterService(typeof(IReferenceMapping), this);
        }

        public virtual void InitInverseReference()
        {
            ReferenceData parentData = this.ReferenceData.TargetData.ReferenceInfos[this.backRole];
            IReferenceReader parentReader = (IReferenceReader)parentData.GetService(typeof(IReferenceReader));
            parentReader.InitInverseReferenceReader<TReference>(this.ReferenceData);
        }

        public ReferenceData ReferenceData
        {
            get { return this.referenceData; }
        }

        public IReferenceReader<TReference> InitInverseReferenceReader(ReferenceData inverseReferenceData)
        {
            throw new NotSupportedException("InverseReferencMapping.GetInverseReferenceReader should never be called...");
        }

        public void InsertDataColumn(IList<System.Data.DataColumn> dataColumns)
        {
            // nothing to to do: everything is done by the parent reference
        }
    }

    //	[Obsolete]
    //	public abstract class SingleInverseReferenceMapping: SingleReferenceFactoryWrapper
    //	{
    //		public SingleInverseReferenceMapping(ReferenceData referenceData, XmlNode metadata)
    //			: base(referenceData, metadata)
    //		{
    //		}
    //	}

    public class InverseReferenceFactory<TReference> :
        InverseReferenceMapping<TReference>
    {
        public InverseReferenceFactory(ReferenceData referenceData, XmlNode metadata)
            :
            base(referenceData, metadata)
        {
           this.ReferenceData.SourceData.Domain.ObjectDependencies.Add(this.ReferenceData.SourceData, new DependantEntity(this.ReferenceData.TargetData,null));  
        }

        public override void InitInverseReference()
        {
            ReferenceData parentData = this.ReferenceData.TargetData.ReferenceInfos[this.backRole];
            IReferenceWriter parentWriter = (IReferenceWriter)parentData.GetService(typeof(IReferenceWriter));
            parentWriter.InitInverseReferenceWriter<TReference>(this.ReferenceData);
        }

        public IReferenceWriter<TReference> InitInverseReferenceWriter(ReferenceData inverseReferenceData)
        {
            throw new NotSupportedException("InverseReferenceFactory.GetInverseReferenceWriter should never be called...");
        }
    }

    //	[Obsolete]
    //	public class SingleInverseReferenceFactory: SingleStoredReferenceFactoryWrapper, IInverseReference
    //	{
    //		private IReferenceWriter referenceWriter;
    //		private string backRole;
    //
    //		public SingleInverseReferenceFactory(ReferenceData referenceData, XmlNode metadata)
    //			: base(referenceData, metadata)
    //		{
    //			XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable());
    //			nsmgr.AddNamespace("typing", "urn:xmd-typing");
    //			nsmgr.AddNamespace("mapping", "urn:xmd-mapping");
    //			this.backRole = metadata.ParentNode.SelectSingleNode("typing:reference/@parent", nsmgr).Value;
    //
    //			this.ReferenceData.RegisterService(typeof(IInverseReference), this);
    //		}
    //
    //		public void InitInverseReference()
    //		{
    //			Debug.Assert(this.referenceWriter == null);
    //			ReferenceData parentData = (ReferenceData)this.ReferenceData.TargetData.ReferenceInfos[this.backRole];
    //			Debug.Assert(parentData != null);
    //			IReferenceWriter parentWriter = (IReferenceWriter)parentData.GetService(typeof(IReferenceWriter));
    //			Debug.Assert(parentWriter != null);
    //			parentWriter.InitInverseReferenceWriter(this.ReferenceData);
    //			this.referenceWriter = (IReferenceWriter)this.ReferenceData.GetService(typeof(IReferenceWriter));
    //		}
    //
    //		protected override IReferenceWriter ReferenceWriter
    //		{
    //			get { return this.referenceWriter; }
    //		}
    //	}

    //  // TODO:
    //	public class SingleInverseReferenceFactory: InverseReferenceFactory, ISingleReferenceReader, ISingleReferenceWriter
    //	{
    //	}
}
